package com.apes.fn.scm.retailOrder.service.retailProcess;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.apes.scm.masterdata.enumeration.model.BusinessParam;
import com.apes.scm.masterdata.enumeration.repository.BusinessParamRepository;
import com.apes.fn.scm.retailOrder.model.RetailOrder;
import com.apes.fn.scm.retailOrder.model.RetailOrderDiscount;
import com.apes.fn.scm.retailOrder.model.RetailOrderItem;
import com.apes.fn.scm.retailOrder.model.RetailOrderPayMethod;
import com.apes.fn.scm.retailOrder.repository.RetailOrderDiscountRepository;
import com.apes.fn.scm.retailOrder.repository.RetailOrderRepository;
import com.apes.fn.server.productReturn.ProductReturn;
import com.apes.fn.server.servicePlan.model.ServicePlan;
import com.apes.fn.server.servicePlan.repository.ServicePlanRepository;
import com.apes.framework.api.DomainService;
import com.apes.framework.api.SpringManager;
import com.apes.framework.jpa.spec.JpaDsl;
import com.apes.framework.plugin.outbox.OutboxEventService;
import com.apes.framework.plugin.outbox.OutboxPayloadWrapper;
import com.apes.framework.util.Arith;
import com.apes.framework.util.LogicalUtil;
import com.apes.framework.util.MapUtil;
import com.apes.scm.account.account.model.AccountingMethod;
import com.apes.scm.account.account.model.InventoryMode;
import com.apes.scm.account.account.service.ProductAccountService;
import com.apes.scm.account.ledger.service.LedgerService;
import com.apes.scm.account.tax.model.Tax;
import com.apes.scm.account.tax.service.TaxService;
import com.apes.scm.invoice.model.Invoice;
import com.apes.scm.invoice.model.InvoiceItem;
import com.apes.scm.invoice.service.InvoiceService;
import com.apes.scm.masterdata.enumeration.repository.EnumerationRepository;
import com.apes.scm.masterdata.finance.model.BankAccount;
import com.apes.scm.masterdata.finance.model.CrossIC;
import com.apes.scm.masterdata.finance.repository.BankAccountRepository;
import com.apes.scm.masterdata.finance.repository.PaymentMethodRepository;
import com.apes.scm.masterdata.frame.model.Store;
import com.apes.scm.masterdata.frame.repository.StoreRepository;
import com.apes.scm.masterdata.party.model.PartyRole;
import com.apes.scm.masterdata.party.repository.PartyRoleRepository;
import com.apes.scm.masterdata.product.model.Product;
import com.apes.scm.masterdata.product.repository.ProductRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.function.Consumer;
import java.util.stream.Collectors;

/**
 * 零售单公共数据处理
 *
 * @author wuq
 * @create 2021-05-21 16:56
 */
public abstract class CommonRetailDataProcess extends DomainService implements RetailProcess {

    @Autowired
    private PartyRoleRepository partyRoleRepository;
    @Autowired
    private ProductRepository productRepository;
    @Autowired
    private ProductAccountService productAccountService;
    @Autowired
    private InvoiceService invoiceService;

    /**
     * 新增之前做的相应处理
     *
     * @param retailOrder 零售单
     * @param consumer    特定的处理器
     */
    public void beforeProcess(RetailOrder retailOrder, Consumer<RetailOrder> consumer) {
        // 第一步：数据检查、收款方式处理、销售明细处理、更新必要字段
        check(retailOrder);

        // 第二步：明细字段公共处理
        updateRetailItem(retailOrder);

        // 第三步：消费分摊、收款方式为其他应收客户转换
        shareBalanceConsumption(retailOrder);
        updatePaymentItemCustomer(retailOrder);

        // 执行特定的处理
        consumer.accept(retailOrder);

        // 场景流判断
        checkScene(retailOrder);
    }

    private void checkScene(RetailOrder retailOrder) {
        if (!Objects.isNull(retailOrder.getScene()) && "RO001".equals(retailOrder.getScene().getId()) && retailOrder.getAmtTotal() < 0) {
            throw new RuntimeException("当场景流为【标准零售】时，金额不能为负数，如果是零售退回，请走零售退回逻辑！");
        }
    }

    private void check(RetailOrder retailOrder) {
        // 收款方式判断
//        updateVipAlliance(retailOrder);                 // 更新会员联盟数据
        updateYearCarPaymentMethod(retailOrder);        // 先处理年卡收款方式
        checkPaymentMethodAccount(retailOrder);         // 对收款方式上面的银行账户与银行账号字段处理

        // 金额相关判断
        retailOrder.checkPaymentMethodSetMoneyEqual();
        retailOrder.checksaleItemsAcountEqual();

        retailOrder.getSaleItems().forEach(retailOrderItem -> {
            retailOrderItem.checkProductDiscountAmount();
            retailOrderItem.getRetailDiscounts().forEach(RetailOrderDiscount::checkDiscountItemAmt);

            // 增加 e保养类订单检查
            if (LogicalUtil.in(retailOrderItem.getProduct().getId(), "0002902247", "0002902284", "0002935068", "0003020877", "0002935072")) {
                retailOrder.setInsuranceDiscountFlag(true);
            }
        });
    }

    private void updateVipAlliance(RetailOrder retailOrder) {
        retailOrder.getPaymentMethodSet().forEach(retailOrderPayMethod -> {
            retailOrderPayMethod.getRetailPayMethodItems().forEach(retailPayMethodItem -> {
                if (retailPayMethodItem.isPlatformDiscountFlag()) {
                    retailPayMethodItem.setVipAlliance(SpringManager.getBean(EnumerationRepository.class).findOne("0000"));
                }
            });
        });

        retailOrder.getSaleItems().forEach(retailOrderItem -> {
            retailOrderItem.getRetailDiscounts().forEach(retailOrderDiscount -> {
                retailOrderDiscount.getRetailDiscountItems().forEach(retailOrderDiscountItem -> {
                    if (retailOrderDiscountItem.isPlatformDiscountFlag()) {
                        retailOrderDiscountItem.setVipAlliance(SpringManager.getBean(EnumerationRepository.class).findOne("0000"));
                    }
                });
            });
        });
    }

    private void updateRetailItem(RetailOrder retailOrder) {
        /* 明细字段处理 */
        String orderType = retailOrder.getOrderType();
        retailOrder.getSaleItems().forEach(
                item -> {
                    if (item.getProductRule() == 10 && item.getSupplier() == null) {
                        throw new RuntimeException("代销带安商品不允许供应商为空");
                    }

                    //默认取 商品上的库存管理信息
                    Product product = productRepository.findOne(item.getProduct().getId());
                    item.setProduct(product);
                    item.setUom(item.getUom() == null ? item.getProduct().getUom() : item.getUom());

                    // 根据老胡要求，需要根据商品组上面的 数量核算标记来计算商品规则
                    int productRule = item.getProduct().getType().equals("product") ? 0 : 30;
                    item.setProductRule(productRule);

                    //折扣信息判断
                    if (item.getRetailDiscounts().size() > 0) {
                        Set set = item.getRetailDiscounts().stream().filter(RetailOrderDiscount::checkNotEmpty).collect(Collectors.toSet());
                        if (set.size() > 0) {
                            item.setRetailDiscounts(set);
                        } else {
                            item.setRetailDiscounts(null);
                        }
                    }
                });
    }

    private void updateYearCarPaymentMethod(RetailOrder retailOrder) {
        // 年卡 收款方式新增 （冲预收）
        Set<RetailOrderPayMethod> payMethods = getPaymentMethod(retailOrder);
        Set<RetailOrderPayMethod> oldPayMethods = retailOrder.getPaymentMethodSet();
        if (payMethods.size() > 0) {
            oldPayMethods.addAll(payMethods);
            retailOrder.setPaymentMethodSet(oldPayMethods);
        }
    }

    /**
     * 设置年卡 收款方式
     *
     * @param retailOrder RetailOrder
     * @return Set<RetailOrderPayMethod>
     */
    public Set<RetailOrderPayMethod> getPaymentMethod(RetailOrder retailOrder) {
        Set<RetailOrderPayMethod> payMethods = new HashSet<>();

        for (RetailOrderItem item : retailOrder.getSaleItems()) {
            if (item.getRetailDiscounts().size() == 0) continue;
            Set<RetailOrderDiscount> set = item.getRetailDiscounts().stream().filter(retailOrderDiscount -> retailOrderDiscount.getCouponProfitAmount() != 0).collect(Collectors.toSet());
            set.forEach(disCount -> {
                RetailOrderPayMethod payMethod = new RetailOrderPayMethod();
                payMethod.setOrder(item.getOrder());

                payMethod.setAmount(disCount.getCouponProfitAmount());
                payMethod.setBillNumber(disCount.getCouponNumber());

                if ("中石化兑换券".equals(disCount.getCouponResource())) {
                    Store store = SpringManager.getBean(StoreRepository.class).findByDept(retailOrder.getDept());
                    if (store.isSinopec()) {
                        payMethod.setPaymentMethodType(SpringManager.getBean(PaymentMethodRepository.class).findOne("56"));
                        payMethod.setCustomer(SpringManager.getBean(PartyRoleRepository.class).findOne("C0002496"));
                    }
                } else {
                    payMethod.setPaymentMethodType(SpringManager.getBean(PaymentMethodRepository.class).findOne("10"));
                }

                payMethods.add(payMethod);
            });
        }
        return payMethods;
    }

    private void checkPaymentMethodAccount(RetailOrder saleOrder) {
        saleOrder.getPaymentMethodSet().stream()
                .filter(payMethod -> "03".equals(payMethod.getPaymentMethodType().getId()))
                .forEach(payMethod -> {
                    if (StringUtils.isEmpty(payMethod.getAccountNumber()) && Objects.isNull(payMethod.getBankAccount())) {
                        throw new RuntimeException("转账的收款方式中，银行账号与银行账户字段同时为空，请检查");
                    }

                    // 如果银行账户与银行账号同时存在就 continue
                    if (!StringUtils.isEmpty(payMethod.getAccountNumber()) && Objects.nonNull(payMethod.getBankAccount()) && !StringUtils.isEmpty(payMethod.getBankAccount().getId()))
                        return;

                    /** 分别处理银行账号与账户 **/
                    if (Objects.nonNull(payMethod.getBankAccount()) && !StringUtils.isEmpty(payMethod.getBankAccount().getId())) {
                        // 根据银行账户获取银行账号
                        payMethod.setAccountNumber(payMethod.getBankAccount().getAccountId());
                    }

                    if (!StringUtils.isEmpty(payMethod.getAccountNumber())) {
                        // 根据银行账号获取账户编码
                        BankAccount bankAccount = SpringManager.getBean(BankAccountRepository.class)
                                .findAll(JpaDsl.toCriteriaByEq("accountId", payMethod.getAccountNumber()))
                                .stream().findFirst()
                                .orElseThrow(() -> new RuntimeException("根据银行账号没有找到对应银行的账户信息"));
                        payMethod.setBankAccount(bankAccount);
                    }
                });
    }

    private void updatePaymentItemCustomer(RetailOrder saleOrder) {
        // 收款方式对其他应收客户做转换
        saleOrder.getPaymentMethodSet().stream()
                .filter(paymentMethod -> Objects.nonNull(paymentMethod.getCustomer()))
                .forEach(paymentMethod -> {
                    paymentMethod.setCustomer(partyRoleRepository.findByPartyIdAndRoleId(paymentMethod.getCustomer().getParty().getId(), "Customer"));
                });

        // 开票方检查
        saleOrder.getPaymentMethodSet().stream()
                .filter(paymentMethod -> Objects.equals(paymentMethod.getPaymentMethodType().getId(), "09"))
                .forEach(paymentMethod -> {
                    if (paymentMethod.getCustomer() == null) throw new RuntimeException("收款方式为【其他应收】时，挂账客户不能为空");
                    // 增加检查开票方
                    List<BusinessParam> businessParams = SpringManager.getBean(BusinessParamRepository.class)
                            .findAllByQueryKeyAndValue("makeInvoice", saleOrder.getCompany().getId(), paymentMethod.getCustomer().getId());
                    if (businessParams.size() > 0) {
                        saleOrder.setMakeInvoice(partyRoleRepository.findOne(businessParams.get(0).getValue2()));
                    }
                });
    }

    /**
     * 余额消费金额分摊
     *
     * @param saleOrder retailOrder
     */
    private RetailOrder shareBalanceConsumption(RetailOrder saleOrder) {
        if (!saleOrder.isBalanceUse()) return saleOrder;

        Set<RetailOrderItem> retailOrderItems = saleOrder.getSaleItems().stream()
                .filter(item -> item.getPriceTotal() - item.getDiscountAmount() - item.getBalanceConsumption() > 0)
                .collect(Collectors.toSet());

        Set<RetailOrderItem> retailOrderItemsNotBalance = saleOrder.getSaleItems().stream()
                .filter(item -> item.getPriceTotal() - item.getDiscountAmount() - item.getBalanceConsumption() <= 0)
                .collect(Collectors.toSet());

        int countItems = retailOrderItems.size();
        double balanceConsumption = saleOrder.getBalanceConsumption();
        double totalItemBalance = 0;

        for (RetailOrderItem item : retailOrderItems) {
            totalItemBalance += item.getPriceTotal() - item.getDiscountAmount() - item.getBalanceConsumption();
        }

        double residue = balanceConsumption;
        int count = 0;
        for (RetailOrderItem item : retailOrderItems) {
            count += 1;
            if (count == countItems) {
                //最后一条数据获取剩余所有 余额消费金额
                item.setBalanceConsumption(residue);
            } else {
                double itemBalanceConsumption = item.getPriceTotal() - item.getDiscountAmount() - item.getBalanceConsumption();
                //向下取小数点整数 占率
                double rateItme = Arith.roundDown(itemBalanceConsumption / totalItemBalance, 4);
                //余额消费金额
                double balance = Arith.roundDown(balanceConsumption * rateItme, 4);
                item.setBalanceConsumption(balance);
                residue -= balance;
            }
        }
        retailOrderItems.addAll(retailOrderItemsNotBalance);
        saleOrder.setSaleItems(retailOrderItems);
        return saleOrder;
    }


    @Override
    public void afterCommonProcess(RetailOrder retailOrder) {
        // 推送计算平台服务费消息
        pushOutboxMsg(retailOrder);

        extracted(retailOrder);

        // 保存之后同步调用
        synInvoker(retailOrder);

        // 其他应收生成账单, 场景流 not in ("RO002", "RO003") 的时候就生成账单
        if (LogicalUtil.notIn(Objects.isNull(retailOrder.getScene()) ? null : retailOrder.getScene().getId(), "RO002", "RO003")) {
            retailFlowInvoice(retailOrder);      //生成账单
        }
    }

    private void extracted(RetailOrder retailOrder) {
        //生成待缴款单,排除定损
        List<RetailOrderPayMethod> retailOrderPayMethodList = retailOrder.getPaymentMethodSet().stream()
                .filter(retailOrderPayMethod -> retailOrderPayMethod.getCustomer() != null)
                .filter(retailOrderPayMethod -> LogicalUtil.notIn(retailOrderPayMethod.getCustomer().getId(), "C0005998", "02532856", "02533043") &&
                        ((partyRoleRepository.findByPartyIdAndRoleId(retailOrderPayMethod.getCustomer().getParty().getId(), "Company") == null ||
                                retailOrder.getCompany().getParty().getId() == retailOrderPayMethod.getCustomer().getParty().getId() ||
                                (!"replacement".equals(retailOrder.getOrderType()) &&
                                        LogicalUtil.notIn(retailOrderPayMethod.getCustomer().getId(), "K1001", "K1003"))) ||
                                ((LogicalUtil.in(retailOrderPayMethod.getCustomer().getId(), "K1001", "K1003")) &&
                                        "replacement".equals(retailOrder.getOrderType()) &&
                                        (retailOrder.getCompany().getParty().getId() == retailOrderPayMethod.getCustomer().getParty().getId() ||
                                                partyRoleRepository.findByPartyIdAndRoleId(retailOrderPayMethod.getCustomer().getParty().getId(), "Company") == null))))
                .collect(Collectors.toList());
        retailOrderPayMethodList.removeIf(Objects::isNull);
        if (retailOrderPayMethodList.isEmpty()) return;
        if (retailOrder.getClaimType() == null) {
            List<Map> mapList = retailOrderPayMethodList.stream()
                    .map(paymentMethod ->
                            MapUtil.mapper("amount", paymentMethod.getAmount(),
                                    "paymentType", paymentMethod.getPaymentMethodType().getId(),
                                    "paymentId", paymentMethod.getPaymentMethodType().getPaymentType().getId())
                    ).collect(Collectors.toList());
            this.invoke("to.prepare.storeCashAndSave", JSON.toJSONString((MapUtil.mapper("orderId", retailOrder.getId(),
                    "deptId", retailOrder.getDept().getId(), "sourceBusinessType", "RetailOrder",
                    "details", mapList))));
        }
    }

    /* 需要做自动归还并且减可用数 的部分： 服务："server"  以及 委托定损, 需要减可用数的部分：普通单:"generalOrder" */
    protected void updateProductAvailable(RetailOrder retailOrder) {
        // 自动归还单
        List<ProductReturn> productReturns = invoke("retail.ProductReturn.create", retailOrder);
        invoke("stock.productReturnList.create", MapUtil.mapped(productReturns));

        setProductAvailable(retailOrder, -1, "零售订单生成");        //占用可用数
    }

    /**
     * 写入商品可用数
     *
     * @param retailOrder 零售单
     * @param type        传入 1 或者 -1
     */
    protected void setProductAvailable(RetailOrder retailOrder, int type, String note) {
        retailOrder.getSaleItems().stream()
                .filter(saleItem -> saleItem.getProductRule() == 0 && saleItem.getLocation() != null)
                .forEach(
                        saleOrderItem -> productAccountService.setProductAvailable(saleOrderItem.getProduct(),
                                saleOrderItem.getLocation(), saleOrderItem.getUom(),
                                type * saleOrderItem.getProductUomQty(),
                                retailOrder.getInnerBusinessType(),
                                retailOrder.getId(), saleOrderItem.getId(),
                                note, saleOrderItem.getLocation().getCompany())
                );
    }

    /**
     * 同步生成平台服务费
     *
     * @param
     */
    private void synInvoker(RetailOrder retailOrder) {
        this.invoke("fn.partnerCheck.calculateRetailFee", MapUtil.mapper("id", retailOrder.getId()));
    }

    private void pushOutboxMsg(RetailOrder retailOrder) {
        JSONObject json = new JSONObject();
        json.put("id", retailOrder.getId());

        //推送定损单回款消息
        if (Objects.nonNull(retailOrder.getScene()) && LogicalUtil.in(retailOrder.getScene().getId(), "RO002", "RO003")) {
            OutboxPayloadWrapper wrapper = new OutboxPayloadWrapper();
            wrapper.setSubscriber("fn.lossQuotation.retailReceived");
            wrapper.setAggregateId("retailReceived:" + retailOrder.getId());
            wrapper.setPayload(json.toJSONString());
            SpringManager.getBean(OutboxEventService.class).sendSaveEvent(wrapper);
        }

        // 推送计算零售单平台服务费消息
//        OutboxPayloadWrapper wrapper = new OutboxPayloadWrapper();
//        wrapper.setSubscriber("fn.partnerCheck.calculateRetailFee");
//        wrapper.setAggregateId(retailOrder.getId()+"-FEE");
//        wrapper.setPayload(json.toJSONString());
//        SpringManager.getBean(OutboxEventService.class).sendSaveEvent(wrapper);

        // 推送零售单扩展表消息
        OutboxPayloadWrapper retailExtension = new OutboxPayloadWrapper();
        retailExtension.setSubscriber("retailOrder.extension.save");
        retailExtension.setAggregateId(retailOrder.getId());
        retailExtension.setPayload(json.toJSONString());
        SpringManager.getBean(OutboxEventService.class).sendSaveEvent(retailExtension);

        //推送平台费用单消息
        OutboxPayloadWrapper retail = new OutboxPayloadWrapper();
        retail.setSubscriber("local:ExpenseService.createExpense");
        retail.setAggregateId(retailOrder.getId());
        retail.setPayload(json.toJSONString());
        SpringManager.getBean(OutboxEventService.class).sendSaveEvent(retail);

    }

    /**
     * 零售生成账单
     * 非异业应收
     *
     * @param retailOrder RetailOrder
     */
    protected void retailFlowInvoice(RetailOrder retailOrder) {
        if (retailOrder.getCustomerExpand() == null) return;

        // 查询折扣明细，异业部分
        Map<CrossIC, List<RetailOrderDiscount>> groupMap = getCrossICListMap(retailOrder);
        if (groupMap.size() > 0) return;

        // 单位客户挂账的部分，也不通过收款方式写账单
        if (checkUnitClientSale(retailOrder.getSource())) return;

        // 零售退货时，判断是否为单位客户
        if ("retailReturn".equals(retailOrder.getOrderType())) {
            String sourceSaleRetailId = retailOrder.getSource();
            RetailOrder sourceRetail = SpringManager.getBean(RetailOrderRepository.class).findOne(sourceSaleRetailId);
            if (checkUnitClientSale(sourceRetail.getSource())) return;
        }

        retailOrder.getPaymentMethodSet().stream()
                .filter(paymentMethod -> "09".equals(paymentMethod.getPaymentMethodType().getId()))
                .collect(Collectors.groupingBy(RetailOrderPayMethod::getCustomer))
                .forEach((customer, item) -> {
                    /*
                    //检查信用额度
                    item.forEach(i->{
                        if(i.getAmount()>getCurAmount(retailOrder.getCompany(), i.getCustomer()).get("curBalance")){
                            throw new RuntimeException(String.format("公司[%s]与客户[%s]间的信用额度不够，请联系财务处理",retailOrder.getCompany().getId(),i.getCustomer().getId()));
                        }
                    });*/

                    //增加占款未清项
                    SpringManager.getBean(LedgerService.class).charge(retailOrder.getCompany(), retailOrder.getDept(), customer,
                            InventoryMode.IM_OWN, AccountingMethod.AM_PURCHASE,
                            retailOrder.getId(), retailOrder.getClass().getSimpleName(), new Date(), "occupy_unsettled",
                            item.stream().mapToDouble(RetailOrderPayMethod::getAmount).sum());

                    createUnitClientInvoice(retailOrder, item, customer);
                });
    }

    /**
     * 检查是否为单位客户挂账
     *
     * @param servicePlanId 服务方案号
     * @return true为单位客户销售   false 非单位客户销售
     */
    private boolean checkUnitClientSale(String servicePlanId) {
        if (StringUtils.isEmpty(servicePlanId)) return false;
        ServicePlan servicePlan = SpringManager.getBean(ServicePlanRepository.class).findOne(servicePlanId);
        if (servicePlan != null) {
            long unitClientCount = servicePlan.getServicePlanItems().stream().filter(servicePlanItem -> Objects.nonNull(servicePlanItem.getUnitClient())).count();
            if (unitClientCount > 0) return true;
        }

        return false;
    }

    /**
     * 查找折扣明细中异业合作的部分
     *
     * @param retailOrder RetailOrder
     * @return
     */
    public Map<CrossIC, List<RetailOrderDiscount>> getCrossICListMap(RetailOrder retailOrder) {
        List<RetailOrderDiscount> retailOrderDiscounts = SpringManager.getBean(RetailOrderDiscountRepository.class).findAllByRetailOrderId(retailOrder.getId());
        return retailOrderDiscounts.stream()
                .filter(RetailOrderDiscount::checkIsCrossIC)
                .collect(Collectors.groupingBy(RetailOrderDiscount::getCrossIC));
    }

    /**
     * 写入单位客户往来账单
     *
     * @param retailOrder 零售订单
     */
    private void createUnitClientInvoice(RetailOrder retailOrder,
                                         List<RetailOrderPayMethod> payMethods,
                                         PartyRole customer) {
        if (retailOrder.getCustomerExpand() == null) return;

        // 账单主表
        Invoice invoice = new Invoice();
        invoice.setCompany(retailOrder.getCompany());
        invoice.setDept(retailOrder.getDept());
        invoice.setContract(null);
        invoice.setPartner(customer);   // 单位客户
        invoice.setScene(retailOrder.getScene());
        invoice.setSource(retailOrder.getId());
        invoice.setSourceBusinessType(RetailOrder.class.getSimpleName());
        invoice.setInventoryMode(InventoryMode.IM_OWN);             //设置库存模式：自有
        invoice.setAccountingMethod(AccountingMethod.AM_PURCHASE);  // 核算方式：经销
        invoice.setCustomerExpand(retailOrder.getCustomerExpand().getId());

        setInvoiceOrigin(retailOrder, invoice);

        //挂账金额
        double unitCustomerMoney = Arith.round(payMethods.stream().mapToDouble(RetailOrderPayMethod::getAmount).sum(), 2);

        // 账单明细
        Set<InvoiceItem> invoiceItems = new HashSet();
        if (unitCustomerMoney == Arith.round(retailOrder.getAmtTotal(), 2)) {
            //全额抵扣 单位客户  定损直赔
            retailOrder.getSaleItems().forEach(saleOrderItem -> {
                InvoiceItem invoiceItem = new InvoiceItem();
                invoiceItem.setProduct(saleOrderItem.getProduct());
                invoiceItem.setPriceUnit(saleOrderItem.getPriceUnit());
                invoiceItem.setQty(saleOrderItem.getProductUomQty());
                invoiceItem.setUom(saleOrderItem.getUom());
                invoiceItem.setTax(saleOrderItem.getTax());
                invoiceItem.setSourceItemId(saleOrderItem.getId());
                invoiceItem.setPriceSubtotal(saleOrderItem.getPriceTotal());    // 商品金额
                invoiceItems.add(invoiceItem);
            });
        } else {
            //获取挂账特殊商品
            Product product = productRepository.findOne("0002256264");
            //普通挂账
            InvoiceItem invoiceItem = new InvoiceItem();
            invoiceItem.setProduct(product);
            invoiceItem.setPriceUnit(unitCustomerMoney);
            invoiceItem.setQty(1);
            invoiceItem.setUom(product.getUom());

            Tax tax = SpringManager.getBean(TaxService.class).getSaleTax(retailOrder.getCompany(), product);
            invoiceItem.setTax(tax);
            invoiceItem.setSourceItemId(retailOrder.getId());
            invoiceItem.setPriceSubtotal(unitCustomerMoney);    // 商品金额
            invoiceItems.add(invoiceItem);
        }

        invoice.setInvoiceItems(invoiceItems);
        invoiceService.save(invoice);
    }

    /**
     * 设置账单来源单号
     *
     * @param retailOrder 零售单
     * @param invoice     账单
     */
    private void setInvoiceOrigin(RetailOrder retailOrder, Invoice invoice) {
        if ("ServicePlan".equals(retailOrder.getSourceBusinessType())) {
            invoice.setOriginBusinessType(retailOrder.getSourceBusinessType());
            invoice.setOrigin(retailOrder.getSource());
        } else if ("RetailReturn".equals(retailOrder.getSourceBusinessType())) {
            // 零售退货的检查是否为服务方案来的
            RetailOrder originRetail = SpringManager.getBean(RetailOrderRepository.class).findOne(retailOrder.getSource());

            if ("ServicePlan".equals(originRetail.getSourceBusinessType())) {
                invoice.setOriginBusinessType(originRetail.getSourceBusinessType());
                invoice.setOrigin(originRetail.getSource());
            } else {
                invoice.setOrigin(originRetail.getId());
                invoice.setOriginBusinessType(RetailOrder.class.getSimpleName());
            }

        } else {
            // 不存在零售来源的情况
            invoice.setOriginBusinessType(RetailOrder.class.getSimpleName());
            invoice.setOrigin(retailOrder.getId());
        }
    }

}
